/*! @file solver_benchmark.h
 *        @brief main : Benchmarking routines that measure the performance
			of CUSP iterative solvers on GPU
*/


/** @fn  benchmark_hybrid_format()
 *                                                                 
 *     @brief  benchmark_hybrid_format : benchmark the performance of GMRES for HYB matrix format
*/  
void benchmark_hybrid_format()
{
	int num_rows, num_cols;
	timer thyb;

	/* create CUSP matrix in HYB format on GPU */
	cusp::hyb_matrix<int, float, cusp::device_memory> A_HYB;
	A_HYB =  A_Host;

	num_rows = A_HYB.num_rows; 
        num_cols = A_HYB.num_cols;	

	printf("\n MATRIX LOADED IN HYB FORMAT : DIMS(%d x %d)",num_rows, num_cols);

	/* Set X Vector to 0*/
	x.resize(num_rows);	
	thrust::fill(x.begin(), x.end(), float(0) );

	/*Creates two monitors verbose and default: for monitoring residual norm ay runtime*/
	cusp::verbose_monitor<float> verbose_monitor(b, input_options.max_iterations, input_options.tolerance);
	cusp::default_monitor<float> default_monitor(b, input_options.max_iterations, input_options.tolerance);

	/*start cuda times*/
	thyb.start_timer();

	/*Start GMRES with verbose or default monitor depending upon the user preference*/
	if(input_options.is_verbose)
		cusp::krylov::gmres(A_HYB, x, b, input_options.restart, verbose_monitor);
	else
		cusp::krylov::gmres(A_HYB, x, b, input_options.restart, default_monitor);
	cudaThreadSynchronize();

	double elapsed_time = thyb.seconds_elapsed();
	printf("\n ELAPSED TIME : %lf SEC FOR %d ITERATIONS \n\n" ,elapsed_time, input_options.max_iterations);
}

/** @fn  benchmark_csr_format()
 *                                                                 
 *     @brief  benchmark_csr_format : benchmark the performance of GMRES for CSR matrix format
*/  
void benchmark_csr_format()
{
	int num_rows, num_cols;
	timer t_csr;

	/* create CUSP matrix in CSR format on GPU */
	cusp::csr_matrix<int, float, cusp::device_memory> A_CSR;
	A_CSR =  A_Host;

	num_rows = A_CSR.num_rows; 
        num_cols = A_CSR.num_cols;	

	printf("\n MATRIX LOADED IN CSR FORMAT : DIMS(%d x %d)",num_rows, num_cols);

	/* Set X Vector to 0*/	
	x.resize(num_rows);	
	thrust::fill(x.begin(), x.end(), float(0) );

	/*Creates two monitors verbose and default: for monitoring residual norm ay runtime*/
	cusp::verbose_monitor<float> verbose_monitor(b, input_options.max_iterations, input_options.tolerance);
	cusp::default_monitor<float> default_monitor(b, input_options.max_iterations, input_options.tolerance);

	t_csr.start_timer();

	/*Start GMRES with verbose or default monitor depending upon the user preference*/	
	if(input_options.is_verbose)
		cusp::krylov::gmres(A_CSR, x, b, input_options.restart, verbose_monitor);
	else
		cusp::krylov::gmres(A_CSR, x, b, input_options.restart, default_monitor);

	cudaThreadSynchronize();

	double elapsed_time = t_csr.seconds_elapsed();
	printf("\n ELAPSED TIME : %lf SEC FOR %d ITERATIONS \n\n" ,elapsed_time, input_options.max_iterations);
}


/** @fn  benchmark_ell_format()
 *                                                                 
 *     @brief  benchmark_ell_format : benchmark the performance of GMRES for ELL matrix format
*/  
void benchmark_ell_format()
{
	int num_rows, num_cols;
	timer t_ell;

	/* create CUSP matrix in ELL format on GPU */
	cusp::ell_matrix<int, float, cusp::device_memory> A_ELL;
	A_ELL =  A_Host;

	num_rows = A_ELL.num_rows; 
        num_cols = A_ELL.num_cols;	

	printf("\n Matrix A Loaded in ELL format : (%d x %d)",num_rows, num_cols);

	/* Set X vector to 0 */
	x.resize(num_rows);	
	thrust::fill(x.begin(), x.end(), float(0) );

	/*Creates two monitors verbose and default: for monitoring residual norm ay runtime*/
	cusp::verbose_monitor<float> verbose_monitor(b, input_options.max_iterations, input_options.tolerance);
	cusp::default_monitor<float> default_monitor(b, input_options.max_iterations, input_options.tolerance);

	t_ell.start_timer();

	 /*Start GMRES with verbose or default monitor depending upon the user preference*/
	if(input_options.is_verbose)
		cusp::krylov::gmres(A_ELL, x, b, input_options.restart, verbose_monitor);
	else
		cusp::krylov::gmres(A_ELL, x, b, input_options.restart, default_monitor);

	cudaThreadSynchronize();
	double elapsed_time = t_ell.seconds_elapsed();
        printf("\n ELAPSED TIME : %lf SEC FOR %d ITERATIONS \n\n" ,elapsed_time, input_options.max_iterations);
}

/** @fn void benchmark_csr_host()
 *
 *     @brief : benchmark GMRES with CSR matrix on host
*/
void benchmark_csr_host()
{
	int num_rows, num_cols;
	timer t_host;

	num_rows = A_Host.num_rows; 
        num_cols = A_Host.num_cols;	

	printf("\n Matrix A Loaded in CSR format @ HOST : (%d x %d)",num_rows, num_cols);

	x_host.resize(num_rows);	
	thrust::fill(x_host.begin(), x_host.end(), float(0) );

	cusp::verbose_monitor<float> verbose_monitor(b_host, input_options.max_iterations, input_options.tolerance);
	cusp::default_monitor<float> default_monitor(b_host, input_options.max_iterations, input_options.tolerance);

	t_host.start_timer();

	if(input_options.is_verbose)
		cusp::krylov::gmres(A_Host, x_host, b_host, input_options.restart, verbose_monitor);
	else
		cusp::krylov::gmres(A_Host, x_host, b_host, input_options.restart, default_monitor);

	cudaThreadSynchronize();
	double elapsed_time = t_host.seconds_elapsed();
	printf("\nELAPSED TIME ON HOST [CSR] : %lf Sec\n\n " ,elapsed_time);
}

/** @fn void cusp_solver_benchmark()
 *                                                                 
 *     @brief cusp_solver_benchmark : Calls ell,hyb and coo benchmark routines
*/  
void cusp_solver_benchmark()
{
	benchmark_hybrid_format();
	benchmark_csr_format();	
	benchmark_ell_format();
}



